home *** CD-ROM | disk | FTP | other *** search
- /*
- C* -- Code generation -- Low level routines.
-
- Routines that start with g_ actually add nodes to the code list.
-
- source: g3.c
- started: February 3, 1986
- version:
- August 5, 1986
- March 7, 1989
-
- PUBLIC DOMAIN SOFTWARE
-
- The CSTAR program was placed in the public domain on June 15, 1991,
- by its author and sole owner,
-
- Edward K. Ream
- 1617 Monroe Street
- Madison, WI 53711
- (608) 257-0802
-
- CSTAR may be used for any commercial or non-commercial purpose.
-
- See cstar.h or cstar.c for a DISCLAIMER OF WARRANTIES.
- */
- #include "cstar.h"
-
- #define ps_opcode(op) ((op <= Q_BRN)? xzp_tab[op] : (char *) NULL)
-
- extern int nd_free;
-
- /*
- Externally visible routines:
- */
- void g_init (void);
- void g_line (int i);
- void g_lit (char *s);
- void g_1lab (int opcode, struct node *p);
- void g_2lab (int opcode, struct node *p1, struct node *p2);
- void g_0 (int opcode);
- void g_1 (int opcode, struct node *p);
- void g_1l (int opcode, struct node *p);
- void g_1l2 (int opcode, struct node *p);
- void g_2 (int opcode, struct node *p1, struct node *p2);
- void g_2l1 (int opcode, struct node *p1, struct node *p2);
- void g_qmove (struct node *loc1, struct node *loc2);
- void g_2l2 (int opcode, struct node *p1, struct node *p2);
- void g_label (struct node * p);
- int mlen (struct node *p);
-
- /*
- Internal routines:
- */
- static void gappend (struct node *p);
-
- void
- g_init(void)
- {
- TICK("g_init");
- }
-
- void
- g_lit(char *s)
- {
- register struct node *q;
-
- /* Create an op node. */
-
- TRACEPB("g_lit", printf("(%s)\n", s));
-
- q = new_cnode();
- q -> c_code = O_LITERAL;
- q -> c_lit = s;
-
- /* Append to code list. */
- gappend(q);
-
- TICKX("g_lit");
- }
-
- void
- g_line(int i)
- {
- register struct node *q;
-
- TRACEPB("g_line", printf("%d\n", i));
-
- /* Create an op node. */
- q = new_cnode();
- q -> c_code = O_LINENUM;
- q -> c_linenum = i;
-
- /* Append to code list. */
- gappend(q);
-
- TICKX("g_line");
- }
-
- /*
- Generate code node for a jump or call to a label.
- */
- void
- g_1lab(int opcode, struct node *p)
- {
- register struct node *q;
-
- TRACEPB("g_1lab", printf("(%d, %p)\n", opcode, p));
-
- if (is_qtok(opcode)) {
- RETURN_VOID("g_1lab");
- }
-
- /* Bump the reference count in the target. */
- if (p -> c_code != O_LABEL && p -> c_code != O_ULABEL) {
- printf("bad code list code %d\n", p -> c_code);
- fatal("g_1lab: bad label type");
- }
- else {
- /* Bump the reference count in the target. */
- p -> c_refcount++;
- }
-
- /* Create a code node to handle the goto. */
- q = new_cnode();
- q -> c_code = opcode;
- q -> c_arg1 = (void *) p;
-
- /* Append to code list. */
- gappend(q);
-
- TICKX("g_1lab");
- }
-
- /*
- generate code for a location with a call/jump to label
- used on 68000 for DBcc Dn, Label, with the location designating
- Dn.
- */
- void
- g_2lab(int opcode, struct node *p1, struct node *p2)
- {
- register struct node *q;
-
- /* Bump the reference count in the target. */
-
- TRACEPB("g_2lab", printf("(%d, %p, %p)\n", opcode, p1, p2));
-
- if (p2 -> c_code != O_LABEL && p2 -> c_code != O_ULABEL) {
- printf("bad code list code %d\n", p2 -> c_code);
- fatal("g_2lab: bad label type");
- }
- else {
- /* Bump the reference count in the target. */
- p2 -> c_refcount++;
- }
-
- /* Create a code node to handle the instruction. */
- q = new_cnode();
- q -> c_code = opcode;
- q -> c_arg1 = p1;
- q -> c_arg2 = p2;
-
- /* Append to code list. */
- gappend(q);
-
- TICKX("g_2lab");
- }
-
- /*
- Generate an explicit X_TOK, or a node having an unknown number
- of arguments
- */
- void
- g_x(int op, struct node *arg1, struct node *arg2, byte len)
- {
- register struct node *q;
-
- /* Create a new code_node. */
-
- TRACEPB("g_x", printf("(%d, %p, %p, %c)\n",
- op, arg1, arg2, len));
-
- q = new_cnode();
- q -> c_code = op;
- q -> c_arg1 = arg1;
- q -> c_arg2 = arg2;
- q -> c_len1 = len;
-
- /* Append to code list. */
- gappend(q);
-
- TICKX("g_x");
- }
-
- /*
- Generate code node for a 0 argument instruction.
- */
- void
- g_0(int opcode)
- {
- register struct node *q;
-
- TRACEPB("g_0", printf("%s (%d)\n", ps_opcode(opcode), opcode));
-
- /* Create an op node. */
- q = new_cnode();
- q -> c_code = opcode;
-
- /* Append to code list. */
- gappend(q);
-
- TICKX("g_0");
- }
-
- /*
- Generate code node for a 1 argument instruction.
- */
- void
- g_1(int opcode, struct node *p)
- {
- register struct node *q;
-
- TRACEPB("g_1",
- printf("%s (%d) ", ps_opcode(opcode), opcode);
- pr_loc(p); printf("\n"));
-
- /* Create a new code_node. */
- q = new_cnode();
- q -> c_code = opcode;
- q -> c_arg1 = p;
-
- /* Append to code list. */
- gappend(q);
-
- TICKX("g_1");
- }
-
- /*
- Generate code node for a 1 argument instruction involving a length.
- */
- void
- g_1l(int opcode, struct node *p)
- {
- register struct node *q;
- register struct type_node *t;
-
- TRACEPB("g_1l",
- printf("%s (%d) ", ps_opcode(opcode), opcode);
- pr_loc(p); printf("\n"));
-
- /* Create a new code_node. */
- q = new_cnode();
- q -> c_code = opcode;
- q -> c_arg1 = p;
- t = p -> n_cltype;
-
- switch (t -> t_typtok) {
- case INT_TYPE:
- case POINTER_TYPE:
- q -> c_len1 = (char) t -> t_tsize;
- break;
- case ARRAY_TYPE:
- case STRUCT_TYPE:
- q -> c_len1 = POINTER_SIZE;
- break;
- default:
- g_error(p, "g_1l: not int or address");
- }
-
- /* Append to code list. */
- gappend(q);
-
- TICKX("g_1l");
- }
-
- /*
- Generate code node for a 1 argument instruction involving a length.
- The length is decreased one notch, as for the ext instruction.
- */
- void
- g_1l2(int opcode, struct node *p)
- {
- register struct node *q;
- register struct type_node *t;
-
- TRACEPB("g_1l2",
- printf("%s (%d) ", ps_opcode(opcode), opcode);
- pr_loc(p); printf("\n"));
-
- /* Create a new code_node. */
- q = new_cnode();
- q -> c_code = opcode;
- q -> c_arg1 = p;
- t = p -> n_cltype;
-
- switch (t -> t_typtok) {
- case INT_TYPE:
- q -> c_len1 = ((char) t -> t_tsize) >> 1;
- break;
- default:
- g_error(p, "g_1l2: not an int");
- }
-
- /* Append to code list. */
- gappend(q);
-
- TICKX("g_1l2");
- }
-
- /*
- Generate code node for a 2 argument instruction.
- */
- void
- g_2(int opcode, struct node *p1, struct node *p2)
- {
- register struct node *q;
-
- TRACEPB("g_2",
- printf("%s (%d) ", ps_opcode(opcode), opcode);
- pr_loc(p1); printf(" "); pr_loc(p2); printf("\n"););
-
- /* Create a new code_node. */
- q = new_cnode();
- q -> c_code = opcode;
- q -> c_arg1 = p1;
- q -> c_arg2 = p2;
-
- /* Append to code list. */
- gappend(q);
-
- TICKX("g_2");
- }
-
- /*
- Derive the effective machine length of a locnode
- This is not the same as the length of the corresponding
- c-language object because arrays and structures stand for
- concealed pointer values in the contexts where this is used.
- */
- int
- mlen(struct node *p)
- {
- register struct type_node *t;
-
- t = p -> n_cltype;
-
- TRACEPB("mlen",
- pr_loc(p); printf("\n");
- pr_type(t));
-
- #ifdef DEBUG
- if (t == NULL) {
- fatal("mlen: untyped loc_node");
- }
- #endif
-
- switch (t -> t_typtok) {
- case INT_TYPE:
- RETURN_INT("mlen", (int) t -> t_tsize);
-
- case POINTER_TYPE:
- case ARRAY_TYPE:
- case STRUCT_TYPE:
- RETURN_INT("mlen", POINTER_SIZE);
-
- default:
- g_error(NULL, "mlen: not int or address");
- RETURN_INT("mlen", POINTER_SIZE);
- }
- }
-
- /*
- Generate code node for a 2 argument instruction involving an
- operator length.
- */
- void
- g_2l1(int opcode, struct node *p1, struct node *p2)
- {
- register struct node *q;
-
- TRACEPB("g_2l1",
- printf("(%s = %d, ", ps_opcode(opcode), opcode);
- pr_loc(p1); printf(" ");
- pr_loc(p2); printf("\n");
- printf("%p, %p); length: %d: type %p: ",
- p1, p2, mlen(p1), p1 -> n_cltype);
- pr_type(p1 -> n_cltype); printf("\n"));
-
- /* Create a new code_node. */
- q = new_cnode();
- q -> c_code = opcode;
- q -> c_arg1 = p1;
- q -> c_arg2 = p2;
-
- q -> c_len1 = (char) mlen(p1);
-
- /* Append to code list. */
- gappend(q);
-
- TICKX("g_2l1");
- }
-
- /*
- Generate code node for a possibly quick move
-
- This handles cases that the peephole (ultimately the opcode
- assigner) can't for one reason or another; e.g. the
- EXCESSLENOK option allows the semantics to be changed.
-
- Take length from the SOURCE operand, which must be properly
- massaged
- */
- void
- g_qmove(register struct node *loc1, register struct node *loc2)
- {
- register struct node *q;
- register struct st_node *id;
- register long i_cnst;
- int f;
-
- /* Create a new code_node. */
-
- TRACEPB("g_qmove", printf("(%p, %p)\n", loc1, loc2));
-
- q = new_cnode();
- q -> c_code = X_MOVE;
- q -> c_arg1 = loc1;
- q -> c_arg2 = loc2;
-
- q -> c_len1 = (char) mlen(loc1);
-
- /* Append to code list. */
- gappend(q);
-
- if (is_cloc(loc1) && (
- #if EXCESSLENOK
- /* if it is allowed to clobber upper part of dreg */
- (f = is_dloc(loc2)) ||
- #endif
- /* if it's faster to load via an available dreg */
- (nd_free && loc2 -> n_mode != VALUE_MODE && mlen(loc2) == 4) )
- ) {
- i_cnst = loc1 -> n_const;
- if (id = loc1 -> n_cid) {
- if (is_rstack(id -> st_sclass) ||
- id->st_sclass == SUE_CLASS) {
- /* i_cnst is now the true constant */
- i_cnst += id -> st_offset;
-
- }
- else {
- /* true constant is label and therefore unknown */
- /* prevent the operation */
- i_cnst = 256;
- }
- }
- if (i_cnst <= 127 && i_cnst >= -128) {
- q -> c_code = X_MOVEQ;
- q -> c_len1 = 0;
- if (!f) {
- /* load a non-value location by loading quick
- a dreg and moving that to the loc */
- q -> c_arg2 = get_dtemp();
- g_2l2(X_MOVE, q -> c_arg2, loc2);
- free_temp(q -> c_arg2);
- }
- }
- }
-
- TICKX("g_qmove");
- }
-
- /*
- Generate code node for a 2 argument instruction involving an
- operator length.
- */
- void
- g_2l2(int opcode, struct node *p1, struct node *p2)
- {
- register struct node *q;
-
- TRACEPB("g_2",
- printf("%s (%d) ", ps_opcode(opcode), opcode);
- pr_loc(p1); printf(" ");
- pr_loc(p2); printf("\n"));
-
- /* Create a new code_node. */
- q = new_cnode();
- q -> c_code = opcode;
- q -> c_arg1 = p1;
- q -> c_arg2 = p2;
-
- q -> c_len1 = (char) mlen(p2);
-
- /* Append to code list. */
- gappend(q);
-
- TICKX("g_2");
- }
-
- /*
- ----- L A B E L R O U T I N E S ----
-
- Label nodes are created during code generation to represent all labels
- generated by the program. Label nodes are created when first
- referenced and are linked into the code linked when and if needed.
-
- Label nodes contain a reference count field so that unneeded labels are
- not output.
-
- Internal (non-user) label nodes contain a count used eventually to
- generate a unique label. The count needs to be assigned when the label
- is first generated so that jumps to the label can be output before the
- label is actually output.
- */
-
- /*
- Link the label node into the code list.
- */
- void
- g_label(struct node * p)
- {
- TRACEPB("g_label", printf("(%p)\n", p));
-
- if (p -> c_code != O_LABEL && p -> c_code != O_ULABEL) {
- printf("bad label type %d\n", p -> c_code);
- fatal("g_label: bad label type");
- }
-
- TRACEP("g_label",
- if (p -> c_code == O_LABEL) {
- printf("L%d:\n", p -> c_labnum);
- }
- else {
- printf("%s:\n", p -> c_labsym);
- }) /* End of TRACE macro. */
-
- /* Append to code list. */
- gappend(p);
-
- TICKX("g_label");
- }
-
- /*
- Append a single code node to the end of the global code list.
- */
- static void
- gappend(struct node *p)
- {
- TRACEP("gappend",
- printf("(%p)\n", p);
- out_list(p));
-
- if (p == NULL) {
- return;
- }
- else if (code_head == NULL) {
- code_head = p;
- code_tail = p;
- }
- else {
- p -> c_back = code_tail;
- code_tail -> c_next = p;
- code_tail = p;
- }
- }
-